package top.zywork.weixin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.multipart.MultipartFile;
import top.zywork.common.HttpUtils;
import top.zywork.common.ImageCompressUtils;
import top.zywork.common.ImageUtils;
import top.zywork.enums.ClientAppEnum;
import top.zywork.enums.ContentTypeEnum;
import top.zywork.enums.MIMETypeEnum;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;

/**
 * 微信内容检测工具类<br/>
 * <p>
 * 创建于2020-02-26<br/>
 *
 * @author 王振宇
 * @version 1.0
 */
@Slf4j
public class WeixinSecCheckUtils {

    public static final String OK_CODE = "0";
    public static final String INVALID_CODE = "87014";
    public static final int IMAGE_MAX_WIDTH = 750;
    public static final int IMAGE_MAX_HEIGHT = 1334;

    /**
     * 对文本进行检测过滤
     * @param redisTemplate
     * @param appId
     * @param appKey
     * @param clientAppEnum
     * @param text
     * @return
     */
    public static boolean checkText(RedisTemplate<String, Object> redisTemplate, String appId, String appKey, ClientAppEnum clientAppEnum, String text) {
        String accessToken = WeixinUtils.getAccessToken(redisTemplate, appId, appKey, clientAppEnum);
        if (StringUtils.isEmpty(accessToken)) {
            log.error("get access token error...");
            return false;
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("content", text);
        String result = HttpUtils.postJSON(WeixinConstants.MSG_SEC_CHECK_URL.replace("{ACCESS_TOKEN}", accessToken), jsonObject.toJSONString());
        return getResult(result);
    }

    /**
     * 对图片进行检测过滤
     * @param redisTemplate
     * @param appId
     * @param appKey
     * @param clientAppEnum
     * @param imageFile 要检测的图片文件，格式支持PNG, JPEG, JPG, GIF, 像素不超过750x1334
     * @return
     */
    public static boolean checkImage(RedisTemplate<String, Object> redisTemplate, String appId, String appKey, ClientAppEnum clientAppEnum, MultipartFile imageFile) {
        try {
            return checkImage(redisTemplate, appId, appKey, clientAppEnum, imageFile.getInputStream());
        } catch (IOException e) {
            log.error("get InputStream from MultipartFile error: {}", e.getMessage());
            return  false;
        }
    }

    /**
     * 对图片进行检测过滤
     * @param redisTemplate
     * @param appId
     * @param appKey
     * @param clientAppEnum
     * @param inputStream 要检测的图片文件，格式支持PNG, JPEG, JPG, GIF, 像素不超过750x1334
     * @return
     */
    public static boolean checkImage(RedisTemplate<String, Object> redisTemplate, String appId, String appKey, ClientAppEnum clientAppEnum, InputStream inputStream) {
        String accessToken = WeixinUtils.getAccessToken(redisTemplate, appId, appKey, clientAppEnum);
        if (StringUtils.isEmpty(accessToken)) {
            log.error("get access token error...");
            return false;
        }
        MIMETypeEnum mimeTypeEnum = ImageUtils.getImageTypeEnum(inputStream);
        if (mimeTypeEnum == null) {
            log.error("can not get the mime type of the image");
            return false;
        }
        inputStream = compressImage(inputStream, mimeTypeEnum.getValue());
        HttpPost httpPost = new HttpPost(WeixinConstants.IMG_SEC_CHECK_URL.replace("{ACCESS_TOKEN}", accessToken));
        httpPost.addHeader("Content-Type", ContentTypeEnum.OCTET_STREAM.getValue());
        try {
            byte[] bytes = new byte[inputStream.available()];
            inputStream.read(bytes);
            httpPost.setEntity(new ByteArrayEntity(bytes, ContentType.create(mimeTypeEnum.getMime())));
        } catch (IOException e) {
            log.error("get the available of InputStream error: {}", e.getMessage());
        }
        String result = HttpUtils.send(HttpUtils.NONE_GET, httpPost, HttpUtils.stringResponseHandler);
        return getResult(result);
    }

    private static InputStream compressImage(InputStream inputStream, String imageType) {
        BufferedImage bufferedImage = ImageUtils.getBufferedImage(inputStream);
        if (bufferedImage != null) {
            if (bufferedImage.getWidth() > IMAGE_MAX_WIDTH || bufferedImage.getHeight() > IMAGE_MAX_HEIGHT) {
                bufferedImage = ImageCompressUtils.compress(bufferedImage, .3f);
                InputStream is = ImageUtils.getInputStream(bufferedImage, imageType);
                return is == null ? inputStream : is;
            }
        }
        return inputStream;
    }

    private static boolean getResult(String result) {
        JSONObject jsonResult = JSON.parseObject(result);
        Object errCode = jsonResult.get(WeixinConstants.ERROR_CODE_STR);
        String errCodeStr = String.valueOf(errCode);
        if (OK_CODE.equals(errCodeStr)) {
            log.info("content or image is valid");
            return true;
        } else if (INVALID_CODE.equals(errCodeStr)) {
            log.error("content or image is invalid");
            return false;
        }
        return false;
    }

}
